﻿using System;

namespace Sencha.Serialization
{
	public static class JsonWriterExtentions
	{
		public static void WriteArrayBegin(this IJsonWriter writer)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(JsonToken.BeginArray);
		}
		public static void WriteArrayEnd(this IJsonWriter writer)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(JsonToken.EndOfArray);
		}
		public static void WriteObjectBegin(this IJsonWriter writer)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(JsonToken.BeginObject);
		}
		public static void WriteObjectEnd(this IJsonWriter writer)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(JsonToken.EndOfObject);
		}
		public static void WriteMember(this IJsonWriter writer, string memberName)
		{
			if (writer == null)
				throw new NullReferenceException();
			if (memberName == null)
				throw new ArgumentNullException("memberName");
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write((JsonMember)memberName);
		}
		public static void WriteMember<T>(this IJsonWriter writer, string memberName, T value)
		{
			if (writer == null)
				throw new NullReferenceException();
			if (memberName == null)
				throw new ArgumentNullException("memberName");
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write((JsonMember)memberName);
			writer.WriteValue<T>(value);
		}
		public static void WriteNumber(this IJsonWriter writer, byte number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(number);
		}
		public static void WriteNumber(this IJsonWriter writer, sbyte number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(number);
		}
		public static void WriteNumber(this IJsonWriter writer, short number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(number);
		}
		public static void WriteNumber(this IJsonWriter writer, ushort number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(number);
		}
		public static void WriteNumber(this IJsonWriter writer, int number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(number);
		}
		public static void WriteNumber(this IJsonWriter writer, uint number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(number);
		}
		public static void WriteNumber(this IJsonWriter writer, long number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(number);
		}
		public static void WriteNumber(this IJsonWriter writer, ulong number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(number);
		}
		public static void WriteNumber(this IJsonWriter writer, float number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(number);
		}
		public static void WriteNumber(this IJsonWriter writer, double number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(number);
		}
		public static void WriteNumber(this IJsonWriter writer, decimal number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(number);
		}
		public static void WriteDateTime(this IJsonWriter writer, DateTime date)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(date);
		}
		public static void WriteBoolean(this IJsonWriter writer, bool value)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(value);
		}
		public static void WriteNumber(this IJsonWriter writer, byte? number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (number == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(number.Value);
		}
		public static void WriteNumber(this IJsonWriter writer, sbyte? number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (number == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(number.Value);
		}
		public static void WriteNumber(this IJsonWriter writer, short? number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (number == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(number.Value);
		}
		public static void WriteNumber(this IJsonWriter writer, ushort? number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (number == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(number.Value);
		}
		public static void WriteNumber(this IJsonWriter writer, int? number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (number == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(number.Value);
		}
		public static void WriteNumber(this IJsonWriter writer, uint? number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (number == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(number.Value);
		}
		public static void WriteNumber(this IJsonWriter writer, long? number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (number == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(number.Value);
		}
		public static void WriteNumber(this IJsonWriter writer, ulong? number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (number == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(number.Value);
		}
		public static void WriteNumber(this IJsonWriter writer, float? number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (number == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(number.Value);
		}
		public static void WriteNumber(this IJsonWriter writer, double? number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (number == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(number.Value);
		}
		public static void WriteNumber(this IJsonWriter writer, decimal? number)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (number == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(number.Value);
		}
		public static void WriteDateTime(this IJsonWriter writer, DateTime? date)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (date == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(date.Value);
		}
		public static void WriteBoolean(this IJsonWriter writer, bool? value)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (value == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(value.Value);
		}
		public static void WriteString(this IJsonWriter writer, string literal)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			if (literal == null)
				writer.Write(JsonToken.Null);
			else
				writer.Write(literal);
		}
		public static void WriteNull(this IJsonWriter writer)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			writer.Write(JsonToken.Null);
		}
		public static void WriteValue<ValueT>(this IJsonWriter writer, ValueT value)
		{
			if (writer == null)
				throw new NullReferenceException();
			System.Diagnostics.Contracts.Contract.EndContractBlock();

			var rwFeature = writer.Context as IJsonSerializer;
			if (rwFeature == null)
				throw new Exceptions.JsonSerializationException(Loc.GetErrorString("Exception_ContextDoesNotSupportHelperMethod", typeof(ISerializationContext), typeof(IJsonSerializer), "WriteValue"), Exceptions.ErrorCode.GenericJsonSerializationException, writer);

			var knownType = writer.Context.DataContract.AddKnownType(typeof(ValueT));
			rwFeature.WriteValue(writer, value, knownType);
		}

		public static void ThrowStackImbalance(IJsonWriter reader)
		{
			throw new Exception("stack imbalance");
		}
	}
}
